package it.mozzicato.apkwizard.model;

import it.mozzicato.apkwizard.*;
import it.mozzicato.apkwizard.dto.*;
import it.mozzicato.apkwizard.utils.PathUtils;

import java.io.*;
import java.util.*;

import javax.swing.JOptionPane;
import javax.swing.table.AbstractTableModel;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.*;

// Creato il 15/mar/2011

/**
 * @author Roberto Mozzicato
 * 
 */
public abstract class AbstractResourceTableModel<T extends BaseResource> extends AbstractTableModel {
	protected enum ResourceOperation {ADD, UPDATE, REMOVE}
	
	protected List<T> activeList;
	protected ResourceTypes activeType;
	protected String projectName;

	/**
	 * Costruttore
	 * 
	 * @param projectName
	 */
	public AbstractResourceTableModel(String projectName) {
		this.projectName = projectName;
	}

	public static <S extends BaseResource> HashMap<String, S> createResMap(List<S> list) {
		HashMap<String, S> ret = new HashMap<String, S>();
		for (S res : list) {
			ret.put(res.getName(), res);
		}
		
		return ret;
	}
	
	protected String getResourcekey(ResourceTypes type, String name, SortableLocale language) {
		if (type == null || name == null)
			return null;

		return type.name() + '_' + name + '_' + language.getLocale();
	}

	@Override
	public int getRowCount() {
		List<T> list = getActiveList();
		return list != null ? list.size() : 0;
	}

	@Override
	public Class<?> getColumnClass(int columnIndex) {
		return String.class;
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		T entry = getItemAt(rowIndex);
		if(entry != null)
			return getField(entry, columnIndex);
		return null;
	}

	@Override
	public void setValueAt(Object value, int rowIndex, int columnIndex) {
		T entry = getItemAt(rowIndex);
		if(entry != null)
			setField(entry, columnIndex, value);
	}

	public T getItemAt(int rowIndex) {
		List<T> list = getActiveList();
		if (list != null && rowIndex >= 0 && rowIndex < list.size())
			return list.get(rowIndex);

		return null;
	}
	
	public List<T> getActiveList() {
		return activeList;
	}

	public ResourceTypes getActiveType() {
		return activeType;
	}
	
	protected void backupAndSave(Document doc, File sourceXml) throws IOException {
		DOMSource domSource = new DOMSource(doc);
		String filePathIntoDecomp = PathUtils.extractProjectSubpath(sourceXml, projectName);
		if(filePathIntoDecomp == null)
			throw new IOException("Unable to extract the path of the file '" + sourceXml + "' inside the 'decomp' directory");
		File backupFile = PathUtils.getFileInProjects(projectName, ApkWizard.SUBPATH_BACKUP, filePathIntoDecomp);
		File backupDir = backupFile.getParentFile();
		File rollbackDir = new File(backupDir.getPath() + ApkWizard.ROLLBACK_SUFFIX);
		
		// We backup the current file only if the resource directory was present in the original file (i.e. we have not created it) 
		if(!rollbackDir.exists()) {
			if(!backupDir.exists() && !backupDir.mkdirs())
				JOptionPane.showMessageDialog(null, "Unable to create resource backup directory: " + backupDir.getAbsolutePath(), "Error", JOptionPane.ERROR_MESSAGE);
			if(sourceXml.exists() && !backupFile.exists()) {
				try {
					PathUtils.copyFile(sourceXml, backupFile);
				}
				catch (IOException e) {
					throw new IOException("Unable to copy file\n" + sourceXml.getAbsolutePath() + "\nto\n" + backupFile.getAbsolutePath());
				}
			}
		}
		
		try {
			StreamResult streamResult = new StreamResult(sourceXml);
			TransformerFactory tf = TransformerFactory.newInstance();				
			Transformer serializer = tf.newTransformer();
			serializer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
//			serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"users.dtd");
			serializer.setOutputProperty(OutputKeys.INDENT,"yes");
			serializer.transform(domSource, streamResult);
		}
		catch (TransformerException e) {
			throw new IOException("Unable to save file '" + sourceXml.getAbsolutePath() + "'");
		}
	}

	protected Document createEmptyResourceFile(File xmlFile) throws ParserConfigurationException {
		DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document ret = db.newDocument();
		ret.setXmlVersion("1.0");
		Element root = ret.createElement("resources");
		ret.appendChild(root);
		return ret;
	}

	protected abstract Object getField(T entry, int columnIndex);

	protected void setField(T entry, int columnIndex, Object value) {}
}
